package control

import (
	"go_gvm_mini/instructions/base"
	"go_gvm_mini/rtda"
	"go_gvm_mini/rtda/heap"
	"reflect"
	"strings"
)

type RETURN struct {
	base.NoOperandsInstruction
}

func (self *RETURN) Execute(jFrame *rtda.JFrame) {
	jFrame.JThread().PopJFrame()
}

type RETURN_T[T int32 | int64 | float32 | float64 | heap.Object] struct {
	base.NoOperandsInstruction
}

func (self *RETURN_T[T]) Execute(jFrame *rtda.JFrame) {
	thread := jFrame.JThread()
	currentJFrame := thread.PopJFrame()
	invokerJFrame := thread.TopJFrame()

	e := reflect.TypeOf(self).Elem().String()
	etype := strings.ReplaceAll(strings.Split(e, "[")[1], "]", "")
	switch etype {
	case "int64":
		val := currentJFrame.OperandStack().PopLong()
		invokerJFrame.OperandStack().PushLong(val)
		break
	case "int32":
		val := currentJFrame.OperandStack().PopInt()
		invokerJFrame.OperandStack().PushInt(val)
		break
	case "float32":
		val := currentJFrame.OperandStack().PopFloat()
		invokerJFrame.OperandStack().PushFloat(val)
		break
	case "float64":
		val := currentJFrame.OperandStack().PopDouble()
		invokerJFrame.OperandStack().PushDouble(val)
		break
	default:
		ref := currentJFrame.OperandStack().PopRef()
		invokerJFrame.OperandStack().PushRef(ref)
	}
}

type IRETURN struct {
	RETURN_T[int32]
}

type LRETURN struct {
	RETURN_T[int64]
}

type FRETURN struct {
	RETURN_T[float32]
}

type DRETURN struct {
	RETURN_T[float64]
}

type ARETURN struct {
	RETURN_T[heap.Object]
}
